#include "PythonBindServer.h"
#include "../exceptions/ObjectNotFoundException.h"
#include "../exceptions/ScriptExecutionException.h"
#include "../utils/TypeConverter.h"
#include "ObjectRegistry.h"
#include "PropertyAccessor.h"
#include "ScriptManager.h"
#include "ServerManager.h"
#include <QApplication>
#include <QDebug>
#include <QObject>
#include <QString>
#include <QVariant>
#include <memory>
#include <pybind11/embed.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

// 定义py命名空间别名
namespace py = pybind11;

// 修复make_unique问题
template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args &&...args) {
  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

PythonBindServer::PythonBindServer() : m_initialized(false) {
  // 初始化各个组件
  m_objectRegistry = make_unique<ObjectRegistry>();
  m_scriptManager = make_unique<ScriptManager>();
  m_propertyAccessor = make_unique<PropertyAccessor>();
}

PythonBindServer::~PythonBindServer() {
  // 析构时确保Python解释器正确清理
  m_interpreter.reset();
}

bool PythonBindServer::initialize() {
  if (m_initialized) {
    return true;
  }

  try {
    // 初始化Python解释器
    m_interpreter = make_unique<pybind11::scoped_interpreter>();

    // 将PythonBindServer实例暴露给Python环境
    py::class_<PythonBindServer>(
        py::module_::import("sys").attr("modules")["__main__"],
        "PythonEnvironmentManager")
        .def("get_object_reference",
             [](PythonBindServer &self, const std::string &objectId) {
               return self.getObjectReference(QString::fromStdString(objectId));
             })
        .def("get_property",
             [](PythonBindServer &self, const std::string &objectId,
                const std::string &propertyName) {
               return self.getProperty(QString::fromStdString(objectId),
                                       QString::fromStdString(propertyName));
             })
        .def("set_property",
             [](PythonBindServer &self, const std::string &objectId,
                const std::string &propertyName, const py::object &value) {
               return self.setProperty(QString::fromStdString(objectId),
                                       QString::fromStdString(propertyName),
                                       value);
             })
        .def("execute_function",
             static_cast<pybind11::object (PythonBindServer::*)(
                 const QString &, const QString &, const pybind11::args &)>(
                 &PythonBindServer::executeFunction))
        .def("execute_function_simple",
             static_cast<pybind11::object (PythonBindServer::*)(
                 const QString &, const QString &)>(
                 &PythonBindServer::executeFunction))
        .def(
            "get_object",
            [](PythonBindServer &self, const std::string &objectId) {
              return self.getObject(QString::fromStdString(objectId));
            },
            py::return_value_policy::reference)
        .def("register_object",
             [](PythonBindServer &self, QObject *obj,
                const std::string &objectId, const std::string &scriptPath) {
               return self.registerObject(obj, QString::fromStdString(objectId),
                                          QString::fromStdString(scriptPath));
             })
        .def("unregister_object",
             static_cast<bool (PythonBindServer::*)(const QString &)>(
                 &PythonBindServer::unregisterObject))
        .def("load_script",
             [](PythonBindServer &self, const std::string &objectId,
                const std::string &scriptPath) {
               return self.loadScript(QString::fromStdString(objectId),
                                      QString::fromStdString(scriptPath));
             })
        .def("unload_script",
             [](PythonBindServer &self, const std::string &objectId) {
               return self.unloadScript(QString::fromStdString(objectId));
             })
        .def("reload_script",
             [](PythonBindServer &self, const std::string &objectId) {
               return self.reloadScript(QString::fromStdString(objectId));
             })
        .def("is_initialized", &PythonBindServer::isInitialized);

    // 将QObject类暴露给Python环境，支持property和setProperty方法
    py::class_<QObject>(py::module_::import("sys").attr("modules")["__main__"],
                        "QObject")
        .def("setProperty",
             [](QObject &self, const std::string &name,
                const py::object &value) {
               // 将Python对象转换为QVariant
               QVariant variant = TypeConverter::pyObjectToQVariant(value);
               return self.setProperty(name.c_str(), variant);
             })
        .def("property",
             [](QObject &self, const std::string &name) {
               QVariant prop = self.property(name.c_str());
               return TypeConverter::qVariantToPyObject(prop);
             })
        .def("objectName",
             [](QObject &self) { return self.objectName().toStdString(); })
        .def("setObjectName", [](QObject &self, const std::string &name) {
          self.setObjectName(QString::fromStdString(name));
        });

    // 将实例暴露给Python环境
    py::globals()["env_manager"] =
        py::cast(this, py::return_value_policy::reference);

    m_initialized = true;
    return true;
  } catch (const std::exception &e) {
    qCritical() << "Python环境初始化失败:" << e.what();
    return false;
  }
}

bool PythonBindServer::isInitialized() const { return m_initialized; }

bool PythonBindServer::registerObject(QObject *obj, const QString &objectId,
                                      const QString &scriptPath) {
  if (!obj) {
    return false;
  }

  if (!m_initialized) {
    if (!initialize()) {
      return false;
    }
  }

  QString id = objectId;
  if (id.isEmpty()) {
    id = generateObjectId(obj);
  }

  // 注册对象到对象注册表
  if (!m_objectRegistry->registerObject(obj, id)) {
    return false;
  }

  // 如果提供了脚本路径，则加载脚本
  if (!scriptPath.isEmpty()) {
    return m_scriptManager->loadScript(id, scriptPath);
  }

  return true;
}

bool PythonBindServer::unregisterObject(const QString &objectId) {
  if (!m_initialized) {
    return false;
  }

  // 卸载相关脚本
  m_scriptManager->unloadScript(objectId);

  // 从对象注册表中注销对象
  return m_objectRegistry->unregisterObject(objectId);
}

bool PythonBindServer::unregisterObject(QObject *obj) {
  if (!obj || !m_initialized) {
    return false;
  }

  QString objectId = m_objectRegistry->getObjectId(obj);
  if (objectId.isEmpty()) {
    return false;
  }

  return unregisterObject(objectId);
}

QObject *PythonBindServer::getObject(const QString &objectId) const {
  if (!m_initialized) {
    return nullptr;
  }

  return m_objectRegistry->getObject(objectId);
}

QString PythonBindServer::getObjectId(QObject *obj) const {
  if (!m_initialized || !obj) {
    return QString();
  }

  return m_objectRegistry->getObjectId(obj);
}

bool PythonBindServer::loadScript(const QString &objectId,
                                  const QString &scriptPath) {
  if (!m_initialized) {
    return false;
  }

  return m_scriptManager->loadScript(objectId, scriptPath);
}

bool PythonBindServer::unloadScript(const QString &objectId) {
  if (!m_initialized) {
    return false;
  }

  return m_scriptManager->unloadScript(objectId);
}

bool PythonBindServer::reloadScript(const QString &objectId) {
  if (!m_initialized) {
    return false;
  }

  return m_scriptManager->reloadScript(objectId);
}

pybind11::object PythonBindServer::getProperty(const QString &objectId,
                                               const QString &propertyName) {
  if (!m_initialized) {
    throw ScriptExecutionException("Python environment not initialized");
  }

  QObject *obj = m_objectRegistry->getObject(objectId);
  if (!obj) {
    throw ObjectNotFoundException(
        QString("Object with ID '%1' not found").arg(objectId));
  }

  return m_propertyAccessor->getProperty(obj, propertyName);
}

bool PythonBindServer::setProperty(const QString &objectId,
                                   const QString &propertyName,
                                   const pybind11::object &value) {
  if (!m_initialized) {
    return false;
  }

  QObject *obj = m_objectRegistry->getObject(objectId);
  if (!obj) {
    throw ObjectNotFoundException(
        QString("Object with ID '%1' not found").arg(objectId));
  }

  return m_propertyAccessor->setProperty(obj, propertyName, value);
}

pybind11::object PythonBindServer::executeFunction(const QString &objectId,
                                                   const QString &functionName,
                                                   const pybind11::args &args) {
  if (!m_initialized) {
    throw ScriptExecutionException("Python environment not initialized");
  }

  return m_scriptManager->executeFunction(objectId, functionName, args);
}

pybind11::object
PythonBindServer::executeFunction(const QString &objectId,
                                  const QString &functionName) {
  if (!m_initialized) {
    throw ScriptExecutionException("Python environment not initialized");
  }

  // 调用带默认参数的版本
  return m_scriptManager->executeFunction(objectId, functionName,
                                          pybind11::tuple());
}

pybind11::object PythonBindServer::getObjectReference(const QString &objectId) {
  if (!m_initialized) {
    throw ScriptExecutionException("Python environment not initialized");
  }

  QObject *obj = m_objectRegistry->getObject(objectId);
  if (!obj) {
    throw ObjectNotFoundException(
        QString("Object with ID '%1' not found").arg(objectId));
  }

  // 将QObject实例暴露给Python环境
  return py::cast(obj, py::return_value_policy::reference);
}

QString PythonBindServer::generateObjectId(QObject *obj) {
  if (!obj) {
    return QString();
  }

  // 生成基于对象地址的唯一ID
  return QString("obj_%1").arg(reinterpret_cast<quintptr>(obj), 0, 16);
}

bool PythonBindServer::isValidObjectId(const QString &objectId) const {
  return !objectId.isEmpty();
}